package main

import (
	"crypto/rand"
	"encoding/gob"
	"errors"
	"fmt"
	"io"
	"log"
	"math/big"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"unicode"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/widget"
	"github.com/tjfoc/gmsm/sm2"
	"github.com/tjfoc/gmsm/sm3"
	"github.com/tjfoc/gmsm/sm4"
)

func init() {
	gob.Register(sm2.P256Sm2())
}

// 判断目录是否存在
func FileExists(filename string) bool {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return false
	}
	return !info.IsDir()
}

func GUI() {
	//生成窗口
	myApp := app.New()

	//设置语言
	// myApp.Settings().SetTheme(&theme.MyTheme{})
	myWindow := myApp.NewWindow("Proxy reencryption local toolkit")
	myWindow.Resize(fyne.NewSize(800, 600))

	//创建子目录（保存公私钥）
	err := os.MkdirAll("./sm2Key", os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}

	//生成公私钥对并保存
	keyLabel := widget.NewLabel("")
	uploadLabel := widget.NewLabel("")
	CSRLabel := widget.NewLabel("")

	generateButton := widget.NewButton("Generate Key Pair", func() {
		//判断用户是否已经生成过公私钥对
		if FileExists("./sm2Key/PrivateFile.dat") {
			keyLabel.SetText("The public and private keys have already been generated, Please do not click again.")
			return
		}

		// 生成公私钥对
		priv, err := sm2.GenerateKey(rand.Reader)
		if err != nil {
			fmt.Println("Failed to generate key pair:", err)
			return
		}
		// 保存公私钥对(dat)
		filePr, err := os.Create("sm2Key/PrivateFile.dat")
		if err != nil {
			log.Fatal(err)
		}
		filePu, err := os.Create("sm2Key/PublicFile.dat")
		if err != nil {
			log.Fatal(err)
		}
		defer filePr.Close()
		defer filePu.Close()

		// 使用 gob 编码器将曲线对象编码为字节切片
		encoderPr := gob.NewEncoder(filePr)
		encoderPu := gob.NewEncoder(filePu)
		err = encoderPr.Encode(priv)
		if err != nil {
			log.Fatal(err)
		}
		err = encoderPu.Encode(priv.PublicKey)
		if err != nil {
			log.Fatal(err)
		}

		// 保存公钥(txt)
		hexStr1 := priv.X.Text(16)
		hexStr2 := priv.Y.Text(16)
		file, err := os.OpenFile("./sm2Key/PublicKey.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
		if err != nil {
			log.Fatalf("无法打开文件: %v", err)
		}
		defer file.Close()
		// 写入内容到文件
		_, err = file.WriteString(hexStr1 + "," + hexStr2)
		if err != nil {
			log.Fatalf("无法写入文件: %v", err)
		}

		keyLabel.SetText("Private and Public Key saved to: sm2Key")
	})

	// 生成CSR
	var numericID string
	entry1 := widget.NewEntry()
	entry1.SetPlaceHolder("Enter numbers only")

	// 设置文本框为只接受数字
	entry1.Validator = func(s string) (err error) {
		for _, r := range s {
			if !unicode.IsDigit(r) {
				return errors.New("validation error: input is not a number")
			}
		}
		// 更新变量值
		numericID = s
		return nil
	}

	// CSR按钮嵌入文本框钮
	content := container.NewVBox(
		entry1,
		widget.NewButton("Generate CSR", func() {
			if entry1.Text == "" || entry1.Validate() != nil {
				myWindow.Canvas().Focus(entry1) // 输入有误时，文本框获得焦点
				return
			}

			//CSR文件的异常处理
			if FileExists("./sm2Key/CSR.dat") {
				CSRLabel.SetText("The CSR file have already been generated, Please do not click again.")
				return
			}

			//密钥对的异常处理
			if FileExists("./sm2Key/PrivateFile.dat") {
				// 读取公钥并生成CSR原文
				data, err := os.ReadFile("./sm2Key/PublicFile.dat")
				if err != nil {
					log.Fatal(err)
				}
				data = append(data, []byte(numericID)...) //组合用户ID,注意加密前的是没有解编码的公钥
				h := sm3.New()
				h.Write([]byte(data))
				sum := h.Sum(nil)

				//保存签名内容
				CSR, err := os.Create("./sm2Key/CSR.dat")
				if err != nil {
					log.Fatalf("无法创建文件: %v", err)
				}
				defer CSR.Close()
				_, err = CSR.Write(sum)
				if err != nil {
					log.Fatalf("无法写入文件: %v", err)
				}

				// 读取私钥
				predepriv, err := os.Open("./sm2Key/PrivateFile.dat")
				if err != nil {
					log.Fatal(err)
				}
				defer predepriv.Close()

				var priv *sm2.PrivateKey
				decoder := gob.NewDecoder(predepriv)
				err = decoder.Decode(&priv)
				if err != nil {
					log.Fatalf("Error decoding: %v", err)
				}

				signfile, err := os.Create("sm2Key/sign.dat")
				if err != nil {
					log.Fatal(err)
				}
				defer signfile.Close()

				sign, err := priv.Sign(rand.Reader, sum, nil) //sm2签名
				if err != nil {
					log.Fatal(err)
				}
				encoderPr := gob.NewEncoder(signfile)
				err = encoderPr.Encode(sign)
				if err != nil {
					log.Fatal(err)
				}

				CSRLabel.SetText("The CSR file have saved to: ./sm2Key")
				return
			}
			CSRLabel.SetText("The public and private keys don't exist, Please generate keys first.")

		}),
	)

	//第二个tab页
	//创建子目录（保存原文件）
	err = os.MkdirAll("./sourceFile", os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}
	destinationDir := "./sourceFile"

	//存储传入文件的文件名
	var srcFileName string

	//上传按钮
	uploadButton := widget.NewButton("Choose and Save File", func() {
		dialog.ShowFileOpen(func(file fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			if file == nil {
				return
			}
			defer file.Close()

			// 获取文件名并设置目标文件路径
			srcFileName = filepath.Base(file.URI().Path())
			destFilePath := filepath.Join(destinationDir, srcFileName)

			// 创建目标文件
			destination, err := os.Create(destFilePath)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			defer destination.Close()

			// 复制文件内容
			_, err = io.Copy(destination, file)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}

			dialog.ShowInformation("Success", "File saved successfully to "+destFilePath, myWindow)
		}, myWindow)
	})

	pageLabel := widget.NewLabel("")
	// 访问分割输入框
	pageContainers := container.NewHBox()

	// 创建一个切片，用于存储所有的输入框
	inputs := make([]*widget.Entry, 9)

	// 创建一个字节切片，用于存储所有输入框的值
	var numbers []int

	// 创建9个输入框，并加入到容器中
	for i := range inputs {
		input := widget.NewEntry()
		input.SetPlaceHolder("Enter Number Only")
		input.Validator = func(s string) error {
			for _, r := range s {
				if !unicode.IsDigit(r) {
					return errors.New("validation error: input is not a number")
				}
			}
			return nil
		}
		pageContainers.Add(input)
		inputs[i] = input
	}

	// 创建一个按钮，当点击时读取输入框的值
	submitButton := widget.NewButton("Submit", func() {
		err := os.MkdirAll("./access/"+srcFileName[:len(srcFileName)-4], os.ModePerm)
		if err != nil {
			log.Fatal(err)
		}

		numbers = numbers[:0] // 清空字节切片
		for _, input := range inputs {
			if input.Text != "" && input.Validate() == nil {
				// 将字符串转换为数字
				num, _ := strconv.Atoi(input.Text)
				numbers = append(numbers, num)
			}
		}
		// 对数字切片进行排序
		sort.Ints(numbers)
		SplitPdf(srcFileName, numbers)
		pageLabel.SetText("The multi-level access control has been successfully set.\nEach tier file is stored in the path:" + "./access/" + srcFileName[:len(srcFileName)-4])
	})

	// 第三个tab页
	pageLabel3 := widget.NewLabel("")

	entryS1 := widget.NewEntry()
	entryS1.SetPlaceHolder("Enter Authorized user ID") //s1
	entryS1.Validator = func(s string) (err error) {
		for _, r := range s {
			if !unicode.IsDigit(r) {
				return errors.New("validation error: input is not a number")
			}
		}
		return nil
	}
	entryS2 := widget.NewEntry()
	entryS2.SetPlaceHolder("Enter Authorized user Public Key") //s2
	entryS2.Validator = func(s string) (err error) {
		for _, r := range s {
			if !(unicode.IsDigit(r) || ('a' <= r && r <= 'f') || ('A' <= r && r <= 'F') || (r == ',')) {
				return errors.New("validation error: input is not a hex number")
			}
		}
		return nil
	}
	entryS3 := widget.NewEntry()
	entryS3.SetPlaceHolder("Enter Authorized pages") //s3
	entryS3.Validator = func(s string) (err error) {
		for _, r := range s {
			if !unicode.IsDigit(r) {
				return errors.New("validation error: input is not a number")
			}
		}
		return nil
	}
	entryS := widget.NewEntry()
	entryS.SetPlaceHolder("Enter Local user ID") //s
	entryS.Validator = func(s string) (err error) {
		for _, r := range s {
			if !unicode.IsDigit(r) {
				return errors.New("validation error: input is not a number")
			}
		}
		return nil
	}

	// 创建按钮
	btn := widget.NewButton("Select the authorization file and encrypt it", func() {
		// 获取文本框的值
		s1 := entryS1.Text
		s2 := entryS2.Text
		s3 := entryS3.Text
		s := entryS.Text

		filePath := "./access/" + srcFileName[:len(srcFileName)-4] + "/" + s3 + ".pdf"

		// 读取文件
		data, err := os.ReadFile(filePath)
		if err != nil {
			fmt.Println("Error reading file:", err)
			return
		}

		// 生成加密密钥并加密文件内容
		k1 := make([]byte, 16)
		_, err = rand.Read(k1)
		if err != nil {
			// 随机数生成失败的错误处理
			fmt.Println("随机数生成失败:", err)
			return
		}
		ecbMsg, err := sm4.Sm4Ecb(k1, data, true) // 加密数据
		if err != nil {
			log.Fatal(err)
		}

		// 保存加密后的数据
		err = os.WriteFile("./access/"+srcFileName[:len(srcFileName)-4]+"/"+s1+"_"+srcFileName[:len(srcFileName)-4]+"_"+s3+"_1.dat", ecbMsg, 0644)
		if err != nil {
			log.Fatal(err)
		}

		predepubA, err := os.Open("./sm2Key/PublicFile.dat")
		if err != nil {
			log.Fatal(err)
		}
		defer predepubA.Close()

		var pubA PublicKey
		decoder := gob.NewDecoder(predepubA)
		err = decoder.Decode(&pubA)
		if err != nil {
			log.Fatalf("Error decoding: %v", err)
		}
		// 找到分隔字符的索引
		index := strings.Index(s2, ",")
		// 分割字符串
		part1 := s2[:index]
		part2 := s2[index+1:] // +1 是为了跳过分隔符本身
		bigIntX := new(big.Int)
		bigIntX.SetString(part1, 16)
		bigIntY := new(big.Int)
		bigIntY.SetString(part2, 16)
		pubB := PublicKey{pubA.Curve, bigIntX, bigIntY}
		clientA := Client{s, pubA}
		clientB := Client{s1, pubB}

		// 加密密钥并重加密, 注意调试完成后要去掉重加密
		ciphertxt, err := clientA.EncryptAsn1(&clientB, k1, rand.Reader, []byte(s+s1))
		if err != nil {
			log.Fatal(err)
		}

		// 保存重加密后的密钥
		err = os.WriteFile("./access/"+srcFileName[:len(srcFileName)-4]+"/"+s1+"_"+srcFileName[:len(srcFileName)-4]+"_"+s3+"_2.dat", ciphertxt, 0644)
		if err != nil {
			log.Fatal(err)
		}

		pageLabel3.SetText("The authorization file has been successfully encrypted\nThe encrypted file is stored in the path:" + "./access/" + srcFileName[:len(srcFileName)-4])
	})

	// 设置布局
	encryption := container.NewVBox(
		entryS1,
		entryS2,
		entryS3,
		entryS,
		btn,
		pageLabel3,
	)

	//第四个tab页
	pageLabelo := widget.NewLabel("")
	pageLabels := widget.NewLabel("")
	pageLabelp := widget.NewLabel("")
	pageLabelv := widget.NewLabel("")

	var oriFileName string
	var signFileName string

	err = os.MkdirAll("./verifyFile", os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}

	btns1 := widget.NewButton("Upload The original file", func() {
		dialog.ShowFileOpen(func(file fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			if file == nil {
				return
			}
			defer file.Close()

			// 获取文件名并设置目标文件路径
			oriFileName = filepath.Base(file.URI().Path())
			destFilePath := filepath.Join("./verifyFile", oriFileName)

			// 创建目标文件
			destination, err := os.Create(destFilePath)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			defer destination.Close()

			// 复制文件内容
			_, err = io.Copy(destination, file)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}

			dialog.ShowInformation("Success", "File saved successfully to "+destFilePath, myWindow)
		}, myWindow)

		pageLabelo.SetText("The original file has been successfully stored in the path: ./verifyFile/" + oriFileName)
	})
	btns2 := widget.NewButton("Upload The sign file", func() {
		dialog.ShowFileOpen(func(file fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			if file == nil {
				return
			}
			defer file.Close()

			// 获取文件名并设置目标文件路径
			signFileName = filepath.Base(file.URI().Path())
			destFilePath := filepath.Join("./verifyFile", signFileName)

			// 创建目标文件
			destination, err := os.Create(destFilePath)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			defer destination.Close()

			// 复制文件内容
			_, err = io.Copy(destination, file)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}

			dialog.ShowInformation("Success", "File saved successfully to "+destFilePath, myWindow)
		}, myWindow)

		pageLabels.SetText("The sign file has been successfully stored in the path: ./verifyFile/" + signFileName)
	})

	btns3 := widget.NewButton("Upload The Publickey file", func() {
		dialog.ShowFileOpen(func(file fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			if file == nil {
				return
			}
			defer file.Close()

			// 获取文件名并设置目标文件路径
			signFileName = filepath.Base(file.URI().Path())
			destFilePath := filepath.Join("./verifyFile", signFileName)

			// 创建目标文件
			destination, err := os.Create(destFilePath)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			defer destination.Close()

			// 复制文件内容
			_, err = io.Copy(destination, file)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			
			dialog.ShowInformation("Success", "File saved successfully to "+destFilePath, myWindow)
		}, myWindow)

		pageLabelp.SetText("The sign file has been successfully stored in the path: ./verifyFile/" + signFileName)
	})

	// entryPK := widget.NewEntry()
	// entryPK.SetPlaceHolder("Enter the public key of the file owner") //s
	verify := widget.NewButton("Verify", func() {
		// puk := entryPK.Text
		orifile, err := os.ReadFile("./verifyFile/" + oriFileName)
		if err != nil {
			log.Fatal(err)
		}

		//读sign文件
		// signfile, err := os.Open("./verifyFile/" + signFileName)
		// if err != nil {
		// 	log.Fatal(err)
		// }
		// defer signfile.Close()

		// var sign []byte
		// decoder := gob.NewDecoder(signfile)
		// err = decoder.Decode(&sign)
		// if err != nil {
		// 	log.Fatal("解码签名失败:", err)
		// }

		sign, err := os.ReadFile("./verifyFile/" + signFileName)
		if err != nil {
			log.Fatal(err)
		}



		predepubA, err := os.Open("./verifyFile/PublicFile.dat")
		if err != nil {
			log.Fatal(err)
		}
		defer predepubA.Close()

		var pubA *sm2.PublicKey
		decoder := gob.NewDecoder(predepubA)
		err = decoder.Decode(&pubA)
		if err != nil {
			log.Fatalf("Error decoding: %v", err)
		}
		// // 找到分隔字符的索引
		// index := strings.Index(puk, ",")
		// // 分割字符串
		// part1 := puk[:index]
		// part2 := puk[index+1:] // +1 是为了跳过分隔符本身
		// bigIntX := new(big.Int)
		// bigIntX.SetString(part1, 16)
		// bigIntY := new(big.Int)
		// bigIntY.SetString(part2, 16)
		// pubA.X = bigIntX
		// pubA.Y = bigIntY

		//验证签名
		isok := pubA.Verify(orifile, sign)
		if isok {
			pageLabelv.SetText("The original file has been verify successfully")
		} else {
			pageLabelv.SetText("The original file verify failed")
		}
	})
	verifysign := container.NewVBox(
		btns1,
		pageLabelo,
		btns2,
		pageLabels,
		btns3,
		pageLabelp,
		// entryPK,
		verify,
		pageLabelv,
	)
	//第五个tab页
	pageLabel4 := widget.NewLabel("")
	pageLabel5 := widget.NewLabel("")
	pageLabel6 := widget.NewLabel("")

	entrySA := widget.NewEntry()
	entrySA.SetPlaceHolder("Enter File owner ID") //s
	entrySA.Validator = func(s string) (err error) {
		for _, r := range s {
			if !unicode.IsDigit(r) {
				return errors.New("validation error: input is not a number")
			}
		}
		return nil
	}

	entrySB := widget.NewEntry()
	entrySB.SetPlaceHolder("Enter Local user ID") //s
	entrySB.Validator = func(s string) (err error) {
		for _, r := range s {
			if !unicode.IsDigit(r) {
				return errors.New("validation error: input is not a number")
			}
		}
		return nil
	}

	//创建接收发来文件的文件夹
	err = os.MkdirAll("./receiveFile", os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}
	err = os.MkdirAll("./authorizationFile", os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}
	var srcFileName1 string
	var srcFileName2 string

	btnre1 := widget.NewButton("Upload The ciphertext file(The file name ends with 1)", func() {
		dialog.ShowFileOpen(func(file fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			if file == nil {
				return
			}
			defer file.Close()

			// 获取文件名并设置目标文件路径
			srcFileName1 = filepath.Base(file.URI().Path())
			destFilePath := filepath.Join("./receiveFile", srcFileName1)

			// 创建目标文件
			destination, err := os.Create(destFilePath)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			defer destination.Close()

			// 复制文件内容
			_, err = io.Copy(destination, file)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}

			dialog.ShowInformation("Success", "File saved successfully to "+destFilePath, myWindow)
		}, myWindow)

		pageLabel4.SetText("The ciphertext file has been successfully stored in the path: ./receiveFile/" + srcFileName1)
	})

	var sa string
	var sb string
	btnre2 := widget.NewButton("Upload The file with the re-encrypted key(The file name ends with 3)", func() {

		sa = entrySA.Text
		sb = entrySB.Text

		dialog.ShowFileOpen(func(file fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			if file == nil {
				return
			}
			defer file.Close()

			// 获取文件名并设置目标文件路径
			srcFileName2 = filepath.Base(file.URI().Path())
			destFilePath := filepath.Join("./receiveFile", srcFileName2)

			// 创建目标文件
			destination, err := os.Create(destFilePath)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}
			defer destination.Close()

			// 复制文件内容
			_, err = io.Copy(destination, file)
			if err != nil {
				dialog.ShowError(err, myWindow)
				return
			}

			dialog.ShowInformation("Success", "File saved successfully to "+destFilePath, myWindow)

		}, myWindow)

		pageLabel5.SetText("Upload The recipherkey file has been successfully stored in the path: ./receiveFile/" + srcFileName1)
	})

	btnre3 := widget.NewButton("Decrypt the authorized file", func() {
		//读入本地用户的公钥和私钥
		predepriB, err := os.Open("./sm2Key/PrivateFile.dat")
		if err != nil {
			log.Fatal(err)
		}
		defer predepriB.Close()

		var priB PrivateKey
		decoder := gob.NewDecoder(predepriB)
		err = decoder.Decode(&priB)
		if err != nil {
			log.Fatalf("Error decoding: %v", err)
		}

		reciphertxt, err := os.ReadFile("./receiveFile/" + srcFileName2)
		if err != nil {
			log.Fatalf("Error read1: %v", err)
		}
		plaintxt, err := priB.DecryptAsn1(reciphertxt, []byte(sa+sb)) //sm2解密
		if err != nil {
			log.Fatalf("Error Decrypt1: %v", err)
		}
		ecbMsg, err := os.ReadFile("./receiveFile/" + srcFileName1)
		if err != nil {
			log.Fatalf("Error read2 %v", err)
		}
		ecbDec, err := sm4.Sm4Ecb(plaintxt, ecbMsg, false) //sm4Ecb模式pksc7填充解密
		if err != nil {
			log.Fatalf("Error Decrypt2: %v", err)
		}

		outputFilePath := "./authorizationFile/" + srcFileName2[5:len(srcFileName2)-4] + ".pdf"
		err = os.WriteFile(outputFilePath, ecbDec, os.ModePerm)
		if err != nil {
			fmt.Println("无法保存PDF文件:", err)
			return
		}

		pageLabel6.SetText("The authorization file has been successfully recrypted\nThe recrypted file is stored in the path:" + "./authorizationFile/")
	})

	// 设置布局
	recryption := container.NewVBox(
		entrySA,
		entrySB,
		btnre1,
		pageLabel4,
		btnre2,
		pageLabel5,
		btnre3,
		pageLabel6,
	)

	// 密钥对生成和公钥选项卡
	tab1 := container.NewVBox(
		widget.NewLabel("Click the button to generate key pair and save as DAT files."),
		generateButton,
		keyLabel,
		widget.NewLabel("To issue a certificate for a key pair, enter the user ID into the text box below and click the button."),
		content,
		CSRLabel,
	)

	//根据用户设置的访问控制分割文件
	tab2 := container.NewVBox(
		widget.NewLabel("Click the button to upload shared file."),
		uploadButton,
		uploadLabel,
		widget.NewLabel("Set access levels, each defined by entering the last page."),
		container.NewVBox(pageContainers, submitButton),
		pageLabel,
	)

	//分配访问权限
	tab3 := container.NewVBox(
		widget.NewLabel("Enter the authorized user ID and upload the corresponding tier file here."),
		encryption,
	)

	//验证数据完整性
	tab4 := container.NewVBox(
		widget.NewLabel("Upload the original file and signature to verify data integrity"),
		verifysign,
	)

	//解密授权文件
	tab5 := container.NewVBox(
		recryption,
	)

	tabs := container.NewAppTabs(
		container.NewTabItem("Public-private Key Generation", tab1),
		container.NewTabItem("Access Settings", tab2),
		container.NewTabItem("File Encryption", tab3),
		container.NewTabItem("Signature Verification", tab4),
		container.NewTabItem("File Decryption", tab5),
	)

	myWindow.SetContent(tabs)
	myWindow.ShowAndRun()
}
